home account info subscribe login search FAQ/help site map contact us


 
Brief Full
 Advanced
      Search
 Search Tips
To access the contents, click the chapter and section titles.

Bug Proofing Visual Basic: A Guide to Error Handling and Prevention
(Publisher: John Wiley & Sons, Inc.)
Author(s): Rod Stephens
ISBN: 0471323519
Publication Date: 11/01/98

Search this book:
 
Previous Table of Contents Next


Use module-level variables only when two routines within the module need to access the same value. Use global variables only when two routines in different modules must access the same value. If possible, avoid global variables by moving the two routines into the same module and using a module-level variable.

Use Specific Data Types

Use the most specific data type possible for a given situation. Do not declare variables of type Object, Control, or Form when you can be more definite.

For example, suppose you have defined a type of form named TaxForm. Suppose also that you have a global subroutine named SetTax that takes as a parameter a TaxForm. You could declare the parameter as a TaxForm, a Form, or an Object. If SetTax will always be passed a TaxForm and never some other kind of form or object, declare the parameter as type TaxForm.

Public Sub SetTax(frmSalesTax As Object)   ‘ Bad.
Public Sub SetTax(frmSalesTax As Form)     ‘ Better.
Public Sub SetTax(frmSalesTax As TaxForm)  ‘ Best.

Declaring the variable with the most specific data type gives Visual Basic more information about the object. That lets it resolve certain object references earlier than it could otherwise. For example, suppose TaxForm includes a TextBox named txtSubTotal and consider this code:

Public Sub SetTax(frmSalesTax As Object)
Dim sub_total As Single

    sub_total = CSng(frmSalesTax.txtSubTotal)
        :
End Sub

When the program is compiled, Visual Basic cannot tell what kind of object the program will pass to SetTax. It cannot know if the frmSalesTax object includes a control named txtSubTotal. For all Visual Basic knows, the program might pass SetTax a reference to a Printer object.

In the following code, on the other hand, Visual Basic knows that the frmSalesTax is a TaxForm object. Because all TaxForm objects contain a TextBox named txtSubTotal, the system knows more precisely how to access the value frmSalesText.txtSubTotal. This lets the program access the TextBox more efficiently. In some examples, the program can access a variable declared with a specific type in one-third the time it takes to access a generic Object variable.

Public Sub SetTax(frmSalesTax As TaxForm)
Dim sub_total As Single

    sub_total = CSng(frmSalesTax.txtSubTotal)
       :
End Sub

Using the most specific data type possible also makes certain kinds of mistakes immediately obvious. If you try to pass a form of type InventoryForm into the SetTax subroutine, Visual Basic will generate a type mismatch error when the code invokes SetTax. This error clearly indicates that the code is trying to pass CalculateTax the wrong kind of object. When you see this error message, the problem is easy to fix.

However, if the routine takes a generic object as a parameter, SetTax will run until it tries to access a property or method that is defined by TaxForm but is not defined by InventoryForm. If both forms define all of the values needed by the routine, SetTax might not generate an error at all. This could cause a very subtle bug. SetTax would look fine internally, but there would be a bug in how the routine was invoked.

Allowing a routine to take a parameter with a weakly defined type can also confuse those who read the code later. Instead of concentrating on a single type of argument, the reader must keep track of many parameter types. He must wonder what the routine will do when the parameter is a form, control, object defined by a class, printer, clipboard, recordset, Nothing, or any of a huge number of other possibilities.

Similar principles apply to variable declarations, function return types, property procedure return types, and any other place the code specifies a data type. The following code legally sets a variable of type Object to reference a new object of the Player class. It would be better to declare the variable to be of type Player.

Dim attacker As Object

    Set attacked = New Player

Keep things efficient and simple by declaring variables using the most specific data type possible.

Use TypeOf and TypeName

Sometimes you must declare an object using a nonspecific data type. For example, you might write a subroutine that must be able to take a parameter that is either a TaxForm or an InventoryForm. To allow the program to pass either type of form to the routine, you should declare the routine’s argument to be of type Form.

Unfortunately, this also allows the program to pass any other kind of form to the routine. Under some circumstances, that might cause some very subtle bugs.

When you use nonspecific data types like this, use Visual Basic’s TypeOf and TypeName statements to verify that the parameter actually has one of the types you expect. For example, the following subroutine ensures that its argument is either a TaxForm or an InventoryForm. If the program passes it any other kind of form, the subroutine raises an exception.

Public Const ERR_WRONG_FORM_TYPE = vbObjectError + 27

Public Sub ResetForm(frm As Form)
    ‘ See if frm is a TaxForm or an InventoryForm.
    If Not ((TypeOf frm Is TaxForm) Or _
            (TypeOf frm Is InventoryForm)) _
    Then
        Err.Raise ERR_WRONG_FORM_TYPE, _
            “MyProject.ResetForm”, _
            “The parameter should be of type TaxForm or ” & _
                “InventoryForm but it actually has type ” & _
                TypeName(frm)
    End If
        :
End Sub

Avoid Variants

An extension of the previous rule, “Use Specific Data Types,” is that you should not use variants. Variants are the least specific of the standard data types and they can contain almost any kind of data. Variants take more memory, are slower, and are often more confusing than other data types. They can lead to particularly confusing data conversion errors.

For example, consider the following subroutine that adds a value to a global total.

Public TotalValue As Variant

Public Sub AddToTotal(new_amount As Variant)
    TotalValue = TotalValue + new_amount
End Sub

Now consider the statements in the following code. The first passes the value 10 to AddToTotal. Because the subroutine expects a variant parameter but 10 is an integer, Visual Basic converts the argument into a variant containing an integer and passes that to AddToTotal. At this point, the variant TotalValue is not yet defined. Because the value being added to TotalValue is an integer, Visual Basic converts TotalValue into a variant holding an integer with default value 0. It adds the new value so TotalValue becomes an integer with value 10.


Previous Table of Contents Next


Products |  Contact Us |  About Us |  Privacy  |  Ad Info  |  Home

Use of this site is subject to certain Terms & Conditions, Copyright © 1996-1999 EarthWeb Inc.
All rights reserved. Reproduction whole or in part in any form or medium without express written permision of EarthWeb is prohibited.